<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>10万条数据存本地且要筛选方案</title>
    <style>
        p {
            font-size: 18px;
            padding: 10px;
            text-align: center;
        }
        .filter{
            padding: 0 0 0 30px;
        }
        li {
            padding: 20px 0;
            border-bottom: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <!-- 
        需求： 有10万条数据从服务器获取，存储在本地，用来展示列表。
              在数据不变的情况下，要根据 创建人 和 类型 来筛选，设计一个方案。
        满足以下条件：
            1. 10万条数据展示列表；
            2. 以最优的方案根据 创建人 和 类型 筛选。
     -->
    
    <p>列表</p>
    <div class="filter">
        <span>筛选类型</span>
        <select onchange="selectType()">
            <option value="no">请选择..</option>
            <option value="min">小</option>
            <option value="mid">中</option>
            <option value="max">大</option>
        </select>
    </div>
    <ul class="list">

    </ul>
</body>
<script>
// 参考：http://caibaojian.com/optimize-large-data.html
/*
    方案：
        1. 分页展示，如果是pc端，展示页码，如果是移动端，用滚动加载
        2. 过滤时，遍历10万条数据，将过滤出来的结果进行分页展示。遍历的过程比较耗时，可以放到web worker中计算
*/

// 下面只做了一半：（纯手写）
// 1. 场景应用在移动端，将10万条数据分页展示，滚动加载；
// 2. 筛选的数据进行分页展示。（筛选的数据通过遍历10万条数据得到，这里耗费性能和事件，可以放入web worker中处理）

// 创建10万条数据
let num = 100000
let arrOrigin = Array.from({length: num}, (v, i) => {
    if (i < 30) return {type: 'min', typeName:'小', id: i+1}
    if (i < 70) return {type: 'mid', typeName:'中', id: i+1}
    return {type: 'max', typeName:'大', id: i+1}
})
console.log('10万条数据', arrOrigin)

// 加载数据
let curPage = 1
let pageSize = 10
let total = num
let maxPage = Math.ceil(arrOrigin.length / pageSize) // 最大页数

let list = [] // 当前数据列表

function loadData(origin){
    let total = origin.length
    let startIndex = (curPage - 1) * pageSize
    let endIndex = (curPage * pageSize) > total ? total : curPage * pageSize

    let listEle = document.querySelector('.list')
    for(let i = startIndex; i < endIndex; i++){
        list.push(origin[i])
        let li = document.createElement('li')
        li.innerText = `${origin[i].id}---${origin[i].typeName}`
        listEle.appendChild(li)
    }    
    let endLi = document.querySelector('.loaded')
    if(endLi && listEle.contains(endLi)) listEle.removeChild(endLi)
    let loadedLi = document.createElement('li')
    loadedLi.className = 'loaded'
    loadedLi.innerText = list.length >= total ? '加载完毕' : 'loading...'
    listEle.appendChild(loadedLi)
    console.log('load-----', 'curPage:',curPage, 'list',list, 'total',total)
}
loadData(arrOrigin)


// 过滤数据
let filterList = []
let filter = false
function selectType(){
    let selectEle = document.querySelector('select')
    let selectedIndex = selectEle.selectedIndex // 获取选中项index
    let value = selectEle.options[selectedIndex].value // 获取选中项value
    prevScrollY = 0
    curPage = 1
    document.querySelector('.list').innerHTML = ''
    list = []
    console.log('select----', prevScrollY, value)
    if(value === 'no'){
        filter = false
        maxPage = Math.ceil(arrOrigin.length / pageSize)
        loadData(arrOrigin)        
    } else {        
        filter = true
        filterList = arrOrigin.filter(item => item.type === value)
        maxPage = Math.ceil(filterList.length / pageSize)
        loadData(filterList)
    }
}

// 滚动处理
let clientHeight = document.documentElement.clientHeight // 可视区高度
let prevScrollY = scrollY // 上一次滚动高度
function handleScroll(){
    console.log('scroll-----', 'scrollY',scrollY, 'prevScrollY',prevScrollY)
    if(scrollY >= prevScrollY) {
        prevScrollY = scrollY
        if(curPage >= maxPage) return
        let loadedLi = document.querySelector('.loaded')
        if(loadedLi.offsetTop <= scrollY + clientHeight){
            curPage++
            loadData(filter?filterList:arrOrigin)
        }
    }
}

// 监听滚动事件
let timeId = null
addEventListener('scroll', function(){
    clearTimeout(timeId)
    timeId = setTimeout(()=>{
        handleScroll()
    }, 100)
})


</script>
</html> 